package com.jinmdz.fmis.api.admin.service;

import com.jinmdz.fmis.api.admin.model.systemmenu.*;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.BusinessSystemDao;
import com.jinmdz.fmis.dao.admin.dao.SystemMenuDao;
import com.jinmdz.fmis.dao.admin.model.businesssystem.BusinessSystemListItem;
import com.jinmdz.fmis.dao.admin.model.systemmenu.SystemMenuEditItem;
import com.jinmdz.fmis.dao.admin.model.systemmenu.SystemMenuListItem;
import com.jinmdz.fmis.mapper.entity.BusinessSystemMenuEntity;
import com.jinmdz.fmis.mapper.mapper.BusinessSystemMenuMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 系统菜单Service
 *
 * @author LiCongLu
 * @date 2020-03-18 15:36
 */
@Service("systemMenuService")
public class SystemMenuService extends BaseService {

    @Resource
    private SystemMenuDao systemMenuDao;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private BusinessSystemMenuMapper businessSystemMenuMapper;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private BusinessSystemDao businessSystemDao;

    /**
     * 加载系统菜单信息
     *
     * @param data 查询条件
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:48
     */
    public BaseResult<ArrayList<SystemMenuListItem>> loadSystemMenuListWithBusinessSystemId(BusinessSystemIdData data) {
        ArrayList<SystemMenuListItem> loadItems = systemMenuDao.listSystemMenuListByBusinessSystemId(data.getBusinessSystemId());
        // 设置字典文本
        dictionaryWrapper.resetDataText(loadItems);
        return successList(loadItems);
    }

    /**
     * 加载系统菜单信息
     *
     * @param data 系统菜单主键
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:48
     */
    public BaseResult<SystemMenuLoadData> loadSystemMenuWithId(SystemMenuIdData data) {
        // 加载数据
        SystemMenuLoadData loadData = new SystemMenuLoadData();

        // 验证业务系统主键
        BusinessSystemListItem systemItem = businessSystemDao.getBusinessSystemListById(data.getBusinessSystemId());
        if (DataUtil.isNull(systemItem) || DataUtil.isNull(systemItem.getId(), systemItem.getVersion())) {
            throw exception("系统主键错误，不存在此系统");
        }

        // 加载所有菜单信息
        ArrayList<SystemMenuListItem> loadItems = systemMenuDao.listSystemMenuListByBusinessSystemId(data.getBusinessSystemId());

        // 记载不可以成父菜单的主键
        ArrayList<Integer> childIds = new ArrayList<>();

        // 加载数据
        if (DataUtil.valid(data.getId())) {
            Integer loadId = data.getId();
            // 查询信息
            SystemMenuEditItem loadItem = systemMenuDao.getSystemMenuEditById(loadId);
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                return failure("主键错误，不存在此系统菜单信息");
            }
            loadData.setMenu(BeanUtil.copy2Bean(loadItem, new SystemMenuSaveData()));
            // 记录当前主键
            childIds.add(loadItem.getId());
            findSystemMenuChildId(loadItems, childIds, loadItem.getId());
        }

        // 记录可选父菜单
        ArrayList<SystemMenuTreeItem> menus = new ArrayList<>();

        // 再次遍历去除子菜单，防止有遗漏
        Iterator<SystemMenuListItem> iterator = loadItems.iterator();
        while (iterator.hasNext()) {
            SystemMenuListItem listItem = iterator.next();
            if (childIds.contains(listItem.getId())) {
                iterator.remove();
                continue;
            }
            menus.add(BeanUtil.copy2Bean(listItem, new SystemMenuTreeItem()));
        }
        loadData.setMenus(menus);

        // 返回响应结果
        return successData(loadData);
    }

    /**
     * 递归查找所有子菜单主键
     *
     * @param loadItems 所有系统菜单
     * @param childIds  子菜单主键集合
     * @param parenId   父菜单主键
     * @return
     * @author LiCongLu
     * @date 2020-03-18 16:05
     */
    private void findSystemMenuChildId(ArrayList<SystemMenuListItem> loadItems, ArrayList<Integer> childIds, Integer parenId) {
        Iterator<SystemMenuListItem> iterator = loadItems.iterator();
        while (iterator.hasNext()) {
            // 判断是否是子菜单
            SystemMenuListItem listItem = iterator.next();
            if (DataUtil.equals(listItem.getParentId(), parenId)) {
                childIds.add(listItem.getId());
                // 删除当前子菜单
                iterator.remove();
                // 地柜子菜单的子菜单
                findSystemMenuChildId(loadItems, childIds, listItem.getId());
            }
        }
    }

    /**
     * 保存系统菜单信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:49
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveSystemMenu(UserItem userItem, SystemMenuSaveData data) throws ActionException {
        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateSystemMenu(userItem, data);
        } else {
            id = insertSystemMenu(userItem, data);
        }
        return success("保存成功");
    }

    /**
     * 插入系统菜单信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:49
     */
    private Integer insertSystemMenu(UserItem userItem, SystemMenuSaveData data) throws ActionException {
        // 创建实体
        BusinessSystemMenuEntity entity = getEntity(userItem, BusinessSystemMenuEntity.class);

        // 验证业务系统主键
        BusinessSystemListItem systemItem = businessSystemDao.getBusinessSystemListById(data.getBusinessSystemId());
        if (DataUtil.isNull(systemItem) || DataUtil.isNull(systemItem.getId(), systemItem.getVersion())) {
            throw exception("系统主键错误，不存在此系统");
        }

        // 赋值数据
        BeanUtil.copy2Bean(data, entity);

        // 对系统菜单信息进行判断处理
        checkSystemMenuValue(entity);

        // 新增系统菜单信息
        businessSystemMenuMapper.insertBusinessSystemMenu(entity);
        // 判断保存系统菜单信息结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存系统菜单信息失败");
        }

        // 添加操作日志
        saveSystemMenuLog(userItem, operationLogCode.getInsert(), data, systemItem, null, entity);

        return entity.getId();
    }

    /**
     * 验证处理系统菜单信息
     *
     * @param entity 系统菜单信息
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:50
     */
    private void checkSystemMenuValue(BusinessSystemMenuEntity entity) throws ActionException {

        // 判断禁用状态
        if (DataUtil.isNull(entity.getDisableState())) {
            entity.setDisableState(0);
        }

        // 判断排序值
        if (DataUtil.isNull(entity.getSort())) {
            entity.setSort(0);
        }

        // 判断父主键
        if (DataUtil.isNull(entity.getParentId())) {
            entity.setParentId(0);
        }

        // 判断菜单名称
        Integer systemMenuId = systemMenuDao.getSystemMenuIdByMenuName(entity.getId(), entity.getBusinessSystemId(), entity.getParentId(), entity.getMenuName());
        if (DataUtil.valid(systemMenuId)) {
            throw exception("存在相同菜单名称");
        }
    }

    /**
     * 添加系统菜单修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param systemItem  系统实体
     * @param oldValue    旧数据
     * @param entity      保存实体
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:51
     */
    private void saveSystemMenuLog(UserItem userItem, Integer logTypeCode, SystemMenuSaveData data, BusinessSystemListItem systemItem, String oldValue, BusinessSystemMenuEntity entity) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存系统菜单信息，系统[{0}]，菜单名称[{1}]，菜单路由[{2}]，菜单重定向路由[{3}]，菜单图标[{4}]，禁用状态[{5}]，备注[{6}]，操作人员[{7}]"
                , systemItem.getSystemName(), entity.getMenuName(), entity.getMenuRoute()
                , entity.getMenuRedirectRoute(), entity.getMenuIcon(), DataUtil.valid(entity.getDisableState()) ? "有效" : "禁用", entity.getRemark()
                , userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), oldValue, JacksonUtil.obj2Json(entity));
    }

    /**
     * 更新系统菜单信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:55
     */
    private void updateSystemMenu(UserItem userItem, SystemMenuSaveData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求系统菜单主键与系统菜单版本号不能为空");
        }

        // 验证业务系统主键
        BusinessSystemListItem systemItem = businessSystemDao.getBusinessSystemListById(data.getBusinessSystemId());
        if (DataUtil.isNull(systemItem) || DataUtil.isNull(systemItem.getId(), systemItem.getVersion())) {
            throw exception("系统主键错误，不存在此系统");
        }

        // 通过主键获取系统菜单信息
        BusinessSystemMenuEntity entity = businessSystemMenuMapper.getBusinessSystemMenuById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("系统菜单主键错误，不存在此系统菜单信息");
        }

        // 验证信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("系统菜单信息"));
        }

        // 判断菜单所属业务系统
        if (!DataUtil.equals(systemItem.getId(), entity.getBusinessSystemId())) {
            throw exception("所属系统主键发生改变！");
        }

        // 记录旧数据
        String oldValue = JacksonUtil.obj2Json(entity);

        // 赋值数据
        BeanUtil.copy2Bean(data, entity);

        // 对系统菜单信息进行判断处理
        checkSystemMenuValue(entity);

        // 更新系统菜单信息
        businessSystemMenuMapper.updateBusinessSystemMenu(entity);

        // 添加操作日志
        saveSystemMenuLog(userItem, operationLogCode.getUpdate(), data, systemItem, oldValue, entity);
    }

    /**
     * 删除指定id的系统菜单信息记录
     *
     * @param userItem 当前帐号
     * @param data     主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:55
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteSystemMenuWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断删除主键集合是否存在
        if (DataUtil.invalid(data)) {
            throw exception("不存在要删除的系统菜单信息");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("系统菜单主键存在重复");
        }

        // 记录系统菜单信息集合
        ArrayList<SystemMenuEditItem> loadItems = new ArrayList<>();

        // 进行遍历删除信息
        for (IdVersionData idData : data) {
            // 通过主键查询系统菜单信息
            SystemMenuEditItem loadItem = systemMenuDao.getSystemMenuEditById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                throw exception("主键错误，不存在此系统菜单信息");
            }

            // 验证系统菜单信息版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("系统菜单信息"));
            }

            // 验证子菜单个数
            Integer menuCount = systemMenuDao.getMenuCountByParentId(loadItem.getId());
            if (DataUtil.valid(menuCount)) {
                throw exception("存在子菜单，不能删除");
            }

            // 删除系统菜单信息
            businessSystemMenuMapper.deletedForBusinessSystemMenu(loadItem.getId(), userItem.getId(), loadItem.getVersion());
            // 记录系统菜单信息
            loadItems.add(loadItem);
        }

        // 添加操作日志信息
        deleteSystemMenuLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author LiCongLu
     * @date 2020-03-18 15:55
     */
    private void deleteSystemMenuLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<SystemMenuEditItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除系统菜单信息，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }
}
